/*
 * Created on 10 mars 2005
 */
package clustering.implementations;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.*;
import java.awt.event.*;
import java.io.FileOutputStream;

//import javax.xml.parsers.DocumentBuilder;
//import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

import clustering.framework.*;
import java.util.*;

/**
 * @author Tudor.Ionescu@supelec.fr

DefaultPresentationEngine

This class draws a tree from an XML document and presents it in a new window. The window is scrollable and contains a grid. The end nodes of the tree are tagged with the name of the files to be clustered. All attributes of the root node are also written on the background of the drawing. This class also saves the tree as a SVG file.

 */
public class DefaultPresentationEngine extends Frame implements IPresentationEngine{
	int offset = 1;
	ArrayList linesAL = new ArrayList();
	ArrayList labelsAL = new ArrayList();
	int x_off = 50, y_off = 25;
	int frame_w = 600, frame_h = 600;
	int x_init_off = 2 * x_off, y_init_off = 2 * y_off;
	String sName = "DefaultPresentationEngine";
	String svgGraph = "";
	Document xmlTree = null;
	Button btnUP = new Button("UP");
	Button btnDOWN = new Button("DOWN");
	Button btnLEFT = new Button("LEFT");
	Button btnRIGHT = new Button("RIGHT");
	public DefaultPresentationEngine(){
		super("Binary Tree Drawer");
		this.setLayout(new BorderLayout());
		this.setSize(frame_w,frame_h);
		this.add(btnLEFT, BorderLayout.WEST);
		btnLEFT.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				x_init_off += x_off;
				repaint();
			}
		});
		this.add(btnUP, BorderLayout.NORTH);
		btnUP.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				y_init_off += y_off;
				repaint();
			}
		});
		this.add(btnDOWN, BorderLayout.SOUTH);
		btnDOWN.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				y_init_off -= y_off;
				repaint();
			}
		});
		this.add(btnRIGHT, BorderLayout.EAST);
		btnRIGHT.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				x_init_off -= x_off;
				repaint();
			}
		});
		this.addWindowListener(new WindowAdapter()
			     {
			       public void windowClosing(WindowEvent evt)
			       {
			       	evt.getWindow().dispose();
			       }
			     });
	}
	public void ParseAndDisplay(String sName, Document xmlTree, String [] fileNames, String outputFilePath)throws Exception{
	    this.xmlTree = xmlTree;
		this.sName = sName;
		this.setName(sName);
		this.setTitle(sName);
		GenerateGraphic(xmlTree.getFirstChild(),0,fileNames,0,0);
		this.show();
		this.repaint();
		FileOutputStream fos = new FileOutputStream(outputFilePath);
		fos.write(GenerateSVG().getBytes());
		fos.close();
	}
	
	// generate the SVG file
	String GenerateSVG(){
	    String svgGraph = "<?xml version=\"1.0\" standalone=\"no\"?>\n" + 
		"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20000303 Stylable//EN\"\n" +
		"\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n" +
		"<svg width=\""+(offset * (x_off + 5))+"\" height=\""+(offset * (y_off + 5))+"\">\n";
		for(int i=0;i<offset * (x_off + 5);i+=x_off){
			svgGraph += "<line x1=\""+i+"\" y1=\"0\" x2=\""+i+"\" y2=\""+(offset * (y_off + 5))+"\" style=\"stroke:rgb(99,99,99);stroke-width:1\"/>\n";
		}
		for(int i=0;i<offset * (y_off + 5);i+=y_off){
			svgGraph += "<line x1=\"0\" y1=\""+i+"\" x2=\""+offset * (x_off + 5)+"\" y2=\""+i+"\" style=\"stroke:rgb(99,99,99);stroke-width:1\"/>\n";
		}
		for(int i=0;i<linesAL.size();i++){
			Line l = (Line)linesAL.get(i);
			svgGraph += "<line x1=\""+(l.x1 + x_init_off)+"\" y1=\""+(l.y1 + y_init_off)+"\" x2=\""+(l.x2 + x_init_off)+"\" y2=\""+(l.y2 + y_init_off)+"\" style=\"stroke:rgb(0,0,0);stroke-width:1\"/>\n";
			svgGraph += "<circle cx=\""+(l.x2 + x_init_off)+"\" cy=\""+(l.y2 + y_init_off)+"\" r=\"4\" stroke=\"black\" stroke-width=\"1\" fill=\"gray\"/>\n";
		}
		for(int i=0;i<labelsAL.size();i++){
			NodeLabel nl = (NodeLabel)labelsAL.get(i);
			svgGraph += "<text x=\""+(nl.x + x_init_off + 8)+"\" y=\""+(nl.y + y_init_off)+"\" font-family=\"Arial\" font-size=\"11\" fill=\"black\">" +nl.text + "</text>\n"; 
		}
		svgGraph += "</svg>";
		return svgGraph;
	}
	
	// draws the tree
	public void paint(Graphics g)
    {
	    Node root = xmlTree.getFirstChild();
	    g.setColor(Color.GRAY);
	    for(int i=0;i<root.getAttributes().getLength();i++){
	        Node attr = root.getAttributes().item(i);
	        String attr_name = attr.getNodeName();
	        String attr_value = attr.getNodeValue();
	        g.drawString(attr_name + "=" + attr_value,x_off,(i+1) * y_off + 40);
	    }
	    frame_h = getHeight();
		frame_w = getWidth();
		g.setColor(Color.LIGHT_GRAY);
		for(int i=0;i<frame_w;i+=x_off){
			g.drawLine(i,0,i,frame_h);
		}
		for(int i=0;i<frame_h;i+=y_off){
			g.drawLine(0,i,frame_w,i);
		}
		g.setColor(Color.BLACK);
		for(int i=0;i<linesAL.size();i++){
			Line l = (Line)linesAL.get(i);
			g.drawLine(l.x1 + x_init_off,l.y1 + y_init_off,l.x2 + x_init_off,l.y2 + y_init_off);
			g.fillOval(l.x2 + x_init_off - 2,l.y2 + y_init_off - 2,5,5);
		}
		for(int i=0;i<labelsAL.size();i++){
			NodeLabel nl = (NodeLabel)labelsAL.get(i);
			g.drawString(nl.text,nl.x + x_init_off + 5,nl.y + y_init_off);
		}
    }
	
	// parses the xml tree with the root in xmlNode and adds Lines and NodeLabels
	// into ArrayLists for drawing a tree
	void GenerateGraphic(Node xmlNode, int depth, String [] fileNames, int x, int y){
	    // compute the coordinates for the current node and add a line to the list
	    int x1 = depth * x_off;
        int y1 = offset * y_off;
	    if(depth > 0){
	        Line l = new Line(x,y, x1, y1);
	    	linesAL.add(l);
	    }	    
		if(!xmlNode.hasChildNodes()){			// terminal node

			// increment the vertical offset
		    offset += 1;
			
			String sId = xmlNode.getAttributes().getNamedItem("id").getNodeValue();
			//String bl = "";
			//if(xmlNode.getAttributes().getNamedItem("bl")!=null){
			//   bl = " [bl=" + xmlNode.getAttributes().getNamedItem("bl").getNodeValue() + "]";
			//}
			int id = Integer.parseInt(sId);
			String sFileName = "";
			if(fileNames[id].indexOf("\\")!=-1){
				sFileName = fileNames[id].substring(fileNames[id].lastIndexOf("\\")+1);
			}else if(fileNames[id].indexOf("/")!=-1){
				sFileName = fileNames[id].substring(fileNames[id].lastIndexOf("/")+1);
			}else sFileName = fileNames[id];
			labelsAL.add(new NodeLabel(sFileName,x1,y1));
		}else{
			// intermediary node
			for(int i=0;i<xmlNode.getChildNodes().getLength();i++){
				GenerateGraphic(xmlNode.getChildNodes().item(i),depth+1,fileNames,x1,y1);
			}			
		}
	}
}
class Line{
	int x1, y1, x2, y2;
	public Line(int x1,int y1, int x2, int y2){
		this.x1 = x1;
		this.x2 = x2;
		this.y1 = y1;
		this.y2 = y2;
	}
}
class NodeLabel{
	String text;
	int x,y;
	public NodeLabel(String text, int x, int y){
		this.text = text;
		this.x = x;
		this.y = y;
	}
}
